// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: linchuan

#include "coin2/exchange/bitflyer_futures/api_util/auth_key.h"

#include <list>

#include "coin2/base/time.h"
#include "coin2/exchange/base/api_util/api_signature.h"
#include "coin2/exchange/base/api_util/json_writer.h"

std::string BitflyerBaseAuth::GetCurrTimeSeconds() {
  return std::to_string(GetCurrentTimestamp() / 1000000);
}

std::string BitflyerBaseAuth::GetSignature(
    const std::string& secret_key,
    const std::string& method,
    const std::string& address,
    const std::string& timestamp,
    const std::string& param) {
  if (secret_key.empty()) {
    throw std::runtime_error("[Bitflyer] API secret key are required");
  }
  std::string cre;
  cre = timestamp + method + address + param;
  return ApiSignatureUtil::GetSignatureByHexHmacSHA256(cre, secret_key);
}

std::string BitflyerWsAuth::CreateSignature() const {
  JsonWriter out;
  auto ts = GetCurrentTimestamp() / 1000000;
  std::string ts_str = std::to_string(ts);
  std::string nonce(ts_str.rbegin(), ts_str.rend());
  nonce = "0000" + nonce;
  std::string signa =
      ApiSignatureUtil::GetSignatureByHexHmacSHA256(ts_str + nonce, key_.secret_key());
  out.PutString("api_key", key_.access_key());
  out.PutInt64("timestamp", ts);
  out.PutString("nonce", nonce);
  out.PutString("signature", signa);

  return fmt::format(
      R"({{"jsonrpc": "2.0", "id": "{}", "method": "auth", "params": {}}})",
      ts_str,
      out.ToJsonString());
}

std::vector<std::pair<std::string, std::string>> BitflyerRestAuth::GetHeaderSet(
    const std::string& method,
    const std::string& address,
    const std::string& param) const {
  std::vector<std::pair<std::string, std::string>> out;
  std::string ts_str = GetCurrTimeSeconds();

  std::string signa = GetSignature(key_.secret_key(), method, address, ts_str, param);
  out.push_back(std::make_pair("ACCESS-KEY", key_.access_key()));
  out.push_back(std::make_pair("ACCESS-SIGN", signa));
  out.push_back(std::make_pair("ACCESS-TIMESTAMP", ts_str));
  return out;
}

AsioHttpContext* BitflyerRestAuth::CreateRequestByGetWithSignature(
    const std::string& address,
    UrlParamsBuilder* builder) {
  std::string ts_str = GetCurrTimeSeconds();
  std::string query_string = builder->ComputeQueryString();
  std::string post_body = builder->ComputePostBody();
  CHECK(post_body.empty());

  std::string target = address;
  if (!query_string.empty()) {
    target += "?" + query_string;
  }

  return AsioHttpContext::NewGet(
      host_,
      port_,
      bind_ip_,
      target,
      GetHeaderSet("GET", target, post_body));
}

AsioHttpContext* BitflyerRestAuth::CreateRequestByPostWithSignature(
    const std::string& address,
    UrlParamsBuilder* builder) {
  std::string ts_str = GetCurrTimeSeconds();
  std::string post_body = builder->ComputePostBody();

  return AsioHttpContext::NewPost(
      host_,
      port_,
      bind_ip_,
      address,
      GetHeaderSet("POST", address, post_body),
      post_body);
}
